{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fcf9686b",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\ruanjiananzhuang\\miniconda3\\envs\\langchain_rag\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "StringPromptValue(text='Tell me a joke about cats')"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 字符串提示词模版: PromptTemplate\n",
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "prompt_template = PromptTemplate.from_template(\"Tell me a joke about {topic}\")\n",
    "\n",
    "prompt_template.invoke({\"topic\": \"cats\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3a572fed",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptValue(messages=[SystemMessage(content='You are a helpful assistant', additional_kwargs={}, response_metadata={}), HumanMessage(content='Tell me a joke about cats', additional_kwargs={}, response_metadata={})])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 聊天提示词模版：ChatPromptTemplate\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "prompt_template = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"You are a helpful assistant\"),\n",
    "    (\"user\", \"Tell me a joke about {topic}\")\n",
    "])\n",
    "\n",
    "prompt_template.invoke({\"topic\": \"cats\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "39e65b08",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptValue(messages=[SystemMessage(content='You are a helpful assistant', additional_kwargs={}, response_metadata={}), HumanMessage(content='hi!', additional_kwargs={}, response_metadata={})])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 消息占位符\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "from langchain_core.messages import HumanMessage\n",
    "\n",
    "prompt_template = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"You are a helpful assistant\"),\n",
    "    MessagesPlaceholder(\"msgs\")\n",
    "])\n",
    "\n",
    "prompt_template.invoke({\"msgs\": [HumanMessage(content=\"hi!\")]})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "58d78a65",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 一种不显式使用 MessagesPlaceholder 类来实现相同功能的替代方法是：，对上面那个Cell 版本的简化写法\n",
    "prompt_template = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"You are a helpful assistant\"),\n",
    "    (\"placeholder\", \"{msgs}\") # <-- This is the changed part\n",
    "])\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f640162",
   "metadata": {},
   "source": [
    "少量示例提示：few-shot-prompting"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcb8b9c9",
   "metadata": {},
   "source": [
    "第二部分：输出解析器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db8a22d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangChain 有许多不同类型的输出解析器。\n",
    "# 最常用的输出解析器是 StrOutputParser，它将模型的输出解析为字符串。\n",
    "# 其他输出解析器包括 JSONOutputParser、CSVOutputParser 等。\n",
    "# 这些输出解析器可以帮助您将模型的输出解析为更结构化的数据类型，例如 JSON 或 CSV。  \n",
    "# 更详细的输出解析器，见官方文档： https://www.langchain.com.cn/docs/concepts/#%E8%BE%93%E5%87%BA%E8%A7%A3%E6%9E%90%E5%99%A8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae62ee2b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 聊天历史：ChatHistory， 很重要的点\n",
    "\n",
    "# 大多数LLM应用程序具有对话界面。 \n",
    "# 对话的一个基本组成部分是能够引用对话中早先引入的信息。\n",
    "# 至少，一个对话系统应该能够直接访问一些过去消息的窗口。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4bf1538e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 文档加载器：DocumentLoader\n",
    "# 很重要的点\n",
    "# 文档手册详见：https://www.langchain.com.cn/docs/how_to/#%E6%96%87%E6%A1%A3%E5%8A%A0%E8%BD%BD%E5%99%A8\n",
    "\n",
    "from langchain_community.document_loaders.csv_loader import CSVLoader\n",
    "\n",
    "loader = CSVLoader(\n",
    "    ...  # <-- Integration specific parameters here\n",
    ")\n",
    "data = loader.load()\n",
    "print(data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30669283",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 文本分割器：TextSplitter\n",
    "# 很重要的点\n",
    "# https://www.langchain.com.cn/docs/how_to/#%E6%96%87%E6%9C%AC%E5%88%86%E5%89%B2%E5%99%A8\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f669235",
   "metadata": {},
   "source": [
    "一旦加载了文档，您通常会希望对其进行转换，以更好地适应您的应用程序。\n",
    "# 例如，您可能希望将文档分割成较小的块，或者将文档转换为向量表示。\n",
    "# 文本分割器：TextSplitter\n",
    "# 很重要的点"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e60b63b8",
   "metadata": {},
   "source": [
    "### 文本分割器的原理\n",
    "1. 将文本拆分成小的、语义上有意义的块（通常是句子）。\n",
    "2. 开始将这些小块组合成一个更大的块，直到达到某个大小（通过某个函数来衡量）。\n",
    "3. 一旦达到该大小，将该块作为独立的文本片段，然后开始创建一个新的文本块，并保持一些重叠（以保持块之间的上下文）。overloap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4990e721",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 嵌入模型\n",
    "# 嵌入模型创建文本片段的向量表示。\n",
    "# 您可以将向量视为一个数字数组，它捕捉了文本的语义含义。 \n",
    "# 通过这种方式表示文本，您可以执行数学运算，从而进行诸如搜索其他在意义上最相似的文本等操作。\n",
    "# 嵌入模型的原理\n",
    "# 1. 输入：嵌入模型的输入是一个文本片段（例如，一个句子或一个段落）。\n",
    "# 2. 处理：模型将文本转换为一个向量表示。这通常涉及到将文本转换为一个数字数组，其中每个数字代表文本中的一个单词或子词。\n",
    "# 3. 输出：嵌入模型的输出是一个向量，它捕捉了输入文本的语义含义。\n",
    "# 4. 数学运算：一旦文本被转换为向量，您就可以执行数学运算，例如计算向量之间的相似度。\n",
    "# 5. 应用：嵌入模型的输出可以用于各种应用，例如搜索、推荐系统和问答系统。\n",
    "\n",
    "# Embeddings类是一个用于与文本嵌入模型接口的类。\n",
    "# 存在许多不同的嵌入大模型供应商（OpenAI、Cohere、Hugging Face等）和本地模型，此类旨在为它们提供标准接口。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e3428d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 向量存储\n",
    "# 存储和搜索非结构化数据的最常见方法之一是将其嵌入并存储生成的嵌入向量，\n",
    "vectorstore = MyVectorStore()\n",
    "retriever = vectorstore.as_retriever()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f775167",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 检索器\n",
    "# 检索器是一个组件，用于从向量存储中检索与输入查询相关的文档。\n",
    "# 它通常与嵌入模型和向量存储结合使用，以实现基于语义的文档检索。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a8e0043",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 键值存储"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4dbaa6f9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 工具\n",
    "tools = [...] # Define a list of tools\n",
    "llm_with_tools = llm.bind_tools(tools)\n",
    "ai_msg = llm_with_tools.invoke(\"do xyz...\")\n",
    "# -> AIMessage(tool_calls=[ToolCall(...), ...], ...)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "25742dd7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 仅使用参数调用\n",
    "# You will want to previously check that the LLM returned tool calls\n",
    "tool_call = ai_msg.tool_calls[0]\n",
    "# ToolCall(args={...}, id=..., ...)\n",
    "tool_output = tool.invoke(tool_call[\"args\"])\n",
    "tool_message = ToolMessage(\n",
    "    content=tool_output,\n",
    "    tool_call_id=tool_call[\"id\"],\n",
    "    name=tool_call[\"name\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "140db9ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 代理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b7b4af7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 回调"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22b5e1c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 流式处理\n",
    "# 这是一个小示例，仅打印包含流式聊天模型输出的事件：\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_anthropic import ChatAnthropic\n",
    "\n",
    "model = ChatAnthropic(model=\"claude-3-sonnet-20240229\")\n",
    "\n",
    "prompt = ChatPromptTemplate.from_template(\"tell me a joke about {topic}\")\n",
    "parser = StrOutputParser()\n",
    "chain = prompt | model | parser\n",
    "\n",
    "async for event in chain.astream_events({\"topic\": \"parrot\"}, version=\"v2\"):\n",
    "    kind = event[\"event\"]\n",
    "    if kind == \"on_chat_model_stream\":\n",
    "        print(event, end=\"|\", flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "015e7cc9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 结构化输出\n",
    "from typing import Optional\n",
    "\n",
    "from pydantic import BaseModel, Field\n",
    "\n",
    "\n",
    "class Joke(BaseModel):\n",
    "    \"\"\"Joke to tell user.\"\"\"\n",
    "\n",
    "    setup: str = Field(description=\"The setup of the joke\")\n",
    "    punchline: str = Field(description=\"The punchline to the joke\")\n",
    "    rating: Optional[int] = Field(description=\"How funny the joke is, from 1 to 10\")\n",
    "\n",
    "structured_llm = llm.with_structured_output(Joke)\n",
    "\n",
    "structured_llm.invoke(\"Tell me a joke about cats\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9ac10930",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain.output_parsers.json import SimpleJsonOutputParser\n",
    "\n",
    "model = ChatOpenAI(\n",
    "    model=\"gpt-4o\",\n",
    "    model_kwargs={ \"response_format\": { \"type\": \"json_object\" } },\n",
    ")\n",
    "\n",
    "prompt = ChatPromptTemplate.from_template(\n",
    "    \"Answer the user's question to the best of your ability.\"\n",
    "    'You must always output a JSON object with an \"answer\" key and a \"followup_question\" key.'\n",
    "    \"{question}\"\n",
    ")\n",
    "\n",
    "chain = prompt | model | SimpleJsonOutputParser()\n",
    "\n",
    "chain.invoke({ \"question\": \"What is the powerhouse of the cell?\" })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "80e204f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 文本分割\n",
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "# RecursiveCharacterTextSplitter, RecursiveJsonSplitter"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain_rag",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
